/******************************************************************************************************
Copyright (C) 2019 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals NMRSpectrum, Molecule, Peaks, Multiplets, NMRAssignments, File, Dir, MolecularAssignmentsParser,
NMRProcessing,
TextStream, Str, Application, mainWindow, FileDialog, AssignmentReporter, Peak, Zip, NMReDATACommon*/
/*jslint plusplus: true, indent: 4*/

/** Default constructor of the converter
 * Defines the file filter
*/
function NMReDATAExporter(aFileName) {
	"use strict";

	this.orgFilePathCorrected = false;
	this.ignoreFilePaths      = false;

	this.CONF = {};
	this.CONF.version           = "1.1";
	this.CONF.endline           = "\\\n";
	this.CONF.tagStart          = "\n>  <";
	this.CONF.protShiftDecimals = 4;
	this.CONF.hetShiftDecimals  = 4;
	this.CONF.jCouplingDecimals = 2;
	this.CONF.jCouplingTol      = 0.1;
	this.CONF.integralDecimals  = 2;
	this.CONF.intensityDecimals = 2;
	this.CONF.reportMeanShifts  = true;
	this.CONF.separator         = ", ";
	this.CONF.corrSeparator     = "/";

	this.sdfText = {};
	this.spectra = [];
	this.moleculeIds = [];
	this.usedSpectralTagNames = {};
	this.assignmentParsers = {};

	this.doc = mainWindow.activeDocument;
	this.docName = this.doc.name.substring(Math.max(this.doc.name.lastIndexOf("/"), this.doc.name.lastIndexOf("\\")) + 1, (this.doc.name.length - 6));

	if (File.exists(aFileName)) {
		File.remove(aFileName);
	}
	this.outputFile = aFileName;

	this.outputDir = new Dir(File.absDirPath(aFileName));
}


NMReDATAExporter.prototype.exportNMReDATA = function () {
	"use strict";

	var i, j, outputPath;

	this.getMoleculeIds();
	this.loadMolecularAssignmentsParsers();
	this.getSpectra();

	for (i = 0; i < this.moleculeIds.length; i++) {
		this.printGeneralTags(i);
		this.printAssignmentTag(i);
		this.printJCouplingsTag(i);
		for (j = 0; j < this.spectra.length; j++) {
			this.printSpectrumTag(i, j);
		}
		this.printProcessingTemplatesTag(i);
		this.completeSDF(i);
		outputPath = this.outputDir.absPath + "/" + this.docName + ((this.moleculeIds.length > 1) ? (1 + i) : "") + ".nmredata.sdf";
		this.saveTextToFile(this.sdfText[this.moleculeIds[i]], outputPath);
		NMReDATACommon.addFilesToZip(outputPath, this.outputFile);
		File.remove(outputPath);
	}
	this.deleteSavedProcessingTemplates();

	return 0;
};


NMReDATAExporter.prototype.printGeneralTags = function (index) {
	"use strict";

	var molecule, formula, rawSmiles, smiles, inChi, sdfPath,
		molId = this.moleculeIds[index];

	molecule = new Molecule(this.doc.getItem(molId));

	this.sdfText[molId] = molecule.getMolfile();

	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_VERSION>\n" + this.CONF.version + this.CONF.endline;

	sdfPath = "Path=" + this.docName + ((this.moleculeIds.length > 1) ? (1 + index) : "") + ".nmredata.sdf";
	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_ID>\n" + sdfPath + this.CONF.endline;

	if (this.spectra && this.spectra.length && this.spectra[0].solvent) {
		this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_SOLVENT>\n" + (this.spectra[0].solvent || " ") + this.CONF.endline;
	}
	if (this.spectra && this.spectra.length && (this.spectra[0].temperature || this.spectra[0].temperature === 0)) {
		this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_TEMPERATURE>\n" + (this.spectra[0].temperature || " ") + this.CONF.endline;
	}

	formula = molecule.molecularFormula();
	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_FORMULA>\n" + formula + this.CONF.endline;

	rawSmiles = molecule.generateSMILES();
	rawSmiles = rawSmiles.replace("\t", " ").trim();

	smiles = rawSmiles.split(" ")[0];
	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_SMILES>\n" + smiles + this.CONF.endline;

	inChi = molecule.generateInChi();
	inChi = inChi.trim();
	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_INCHI>\n" + inChi + this.CONF.endline;
};


NMReDATAExporter.prototype.printAssignmentTag = function (index) {
	"use strict";

	var i, aAssignment,
		text = "",
		molId = this.moleculeIds[index];

	molId = this.moleculeIds[index];

	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_ASSIGNMENT>\n";

	for (i = 0; i < this.assignmentParsers[molId].assignments.length; i++) {
		aAssignment = this.assignmentParsers[molId].assignments[i];
		text += this.parseAtomAssignment(aAssignment);
	}
	this.sdfText[molId] += text;
};


NMReDATAExporter.prototype.parseAtomAssignment = function (aAssignment) {
	"use strict";

	var i, decimals,
		text = "";

	decimals = (aAssignment.element === "H" ? this.CONF.protShiftDecimals : this.CONF.hetShiftDecimals);

	if (aAssignment.shift && aAssignment.shift.length) {
		text += aAssignment.atom.labelNMReDATA;
		for (i = 0; i < aAssignment.shift.length; i++) {
			text += this.CONF.separator;
			text += aAssignment.shift[i].shift.toFixed(decimals);
		}
		text += this.CONF.separator + aAssignment.atom.indexNMReDATA + this.CONF.endline;
	}

	return text;
};


NMReDATAExporter.prototype.printJCouplingsTag = function (index) {
	"use strict";

	var i,
		jCouplings = [],
		text = "",
		molId = this.moleculeIds[index];

	molId = this.moleculeIds[index];

	this.sdfText[molId] += this.CONF.tagStart + "NMREDATA_J>\n";

	jCouplings = this.parseJCouplings(molId);
	jCouplings = this.removeDuplicatedJCouplings(jCouplings);

	for (i = 0; i < jCouplings.length; i++) {
		text += jCouplings[i].atom1.labelNMReDATA + this.CONF.separator;
		text += jCouplings[i].atom2.labelNMReDATA + this.CONF.separator;
		text += jCouplings[i].value.toFixed(this.CONF.jCouplingDecimals) + this.CONF.separator;
		text += "nb=" + jCouplings[i].bondsBetween + this.CONF.endline;
	}

	this.sdfText[molId] += text;
};


NMReDATAExporter.prototype.parseJCouplings = function (molId) {
	"use strict";

	var i, j, aJcoupling, partner, aAssignment,
		molecule = new Molecule(this.doc.getItem(molId)),
		jCouplings = [];

	for (i = 0; i < this.assignmentParsers[molId].assignments.length; i++) {
		aAssignment = this.assignmentParsers[molId].assignments[i];

		if (aAssignment.couplings && aAssignment.couplings.js) {
			for (j = 0; j < aAssignment.couplings.js.length; j++) {
				aJcoupling = {};
				aJcoupling.value = aAssignment.couplings.js[j].value;
				aJcoupling.atom1 = aAssignment.atom;
				partner = this.assignmentParsers[molId].getFromAtom(aAssignment.couplings.js[j].atom);
				if (partner) {
					aJcoupling.atom2 = partner.atom;
					aJcoupling.bondsBetween = molecule.distanceBetween(aJcoupling.atom1.index, aJcoupling.atom2.index);
					if (!aJcoupling.atom1.explicit) {
						aJcoupling.bondsBetween++;
					}
					if (!aJcoupling.atom2.explicit) {
						aJcoupling.bondsBetween++;
					}
					jCouplings.push(aJcoupling);
				}
			}
		}
	}

	return jCouplings;
};


NMReDATAExporter.prototype.removeDuplicatedJCouplings = function (jCouplings) {
	"use strict";

	var i, j, aRef, aTest;

	for (i = 0; i < jCouplings.length - 1; i++) {
		aRef = jCouplings[i];
		for (j = 1 + i; j < jCouplings.length; j++) {
			aTest = jCouplings[j];
			if (aRef && aTest && aRef.value === aTest.value) {
				if (NMReDATACommon.compareObjects(aRef.atom1, aTest.atom2) && NMReDATACommon.compareObjects(aRef.atom2, aTest.atom1)) {
					jCouplings.splice(j, 1);
				}
			}
		}
	}

	return jCouplings;
};


NMReDATAExporter.prototype.printSpectrumTag = function (index, spectrumIndex) {
	"use strict";

	var assignments, molecule, corType, md5, relativeLocation, spectrumTagName,
		molId = this.moleculeIds[index],
		spectrumData = this.spectra[spectrumIndex];

	molecule = new Molecule(this.doc.getItem(molId));
	assignments = new NMRAssignments(molecule);
	spectrumTagName = this.getSpectrumTagName(spectrumData, molId);
	this.spectra[spectrumIndex].spectrumTagName = spectrumTagName;

	this.sdfText[molId] += this.CONF.tagStart + spectrumTagName + ">\n";

	this.sdfText[molId] += "Larmor=" + spectrumData.frequency + this.CONF.endline;
	if (spectrumData.type === "2D") {
		if (spectrumData.experimentType === "Unknown") {
			corType = "Unknown";
		} else {
			corType = spectrumData.experimentType.substring(3);
		}
		this.sdfText[molId] += "CorType=" + corType + this.CONF.endline;
	}

	relativeLocation = this.getRelativeSpectrumLocation(spectrumData.originalFileName);
	this.sdfText[molId] += "Spectrum_Location=" + relativeLocation + this.CONF.endline;

	md5 = this.calculateMD5(spectrumData.originalFileName);
	this.sdfText[molId] += "MD5=" + md5 + this.CONF.endline; //To be corrected

	this.sdfText[molId] += "Pulseprogram=" + spectrumData.pulseProgram + this.CONF.endline;

	if (spectrumData.type === "1D") {
		if (spectrumData.multiplets.count > 0) {
			this.print1DMultiplets(spectrumData, molId);
		} else if (spectrumData.peaks.count > 0) {
			this.print1DPeaks(spectrumData, molId);
		}
	} else if (spectrumData.type === "2D") {
		if (spectrumData.multiplets.count > 0) {
			this.print2DMultiplets(spectrumData, molId);
		} else if (spectrumData.peaks.count > 0) {
			this.print2DPeaks(spectrumData, molId);
		}
	}
};


NMReDATAExporter.prototype.getRelativeSpectrumLocation = function (aCurrentLocation) {
	"use strict";

	var dataDir, baseDirPath, relativeLocation;

	if (this.rootPathEq) {
		relativeLocation = aCurrentLocation.replace(this.rootPathEq.curr, "file:.");
	} else if (!this.ignoreFilePaths) {
		dataDir = new Dir(File.absDirPath(aCurrentLocation));
		if (aCurrentLocation.endsWith("1r") || aCurrentLocation.endsWith("2rr") || aCurrentLocation.endsWith("3rrr")) {
			dataDir.cdUp();
			dataDir.cdUp();
		}
		dataDir.cdUp();
		baseDirPath = dataDir.absPath;
		relativeLocation = aCurrentLocation.replace(baseDirPath, "file:.");
	} else {
		relativeLocation = "file:";
	}
	return relativeLocation;
};


NMReDATAExporter.prototype.print2DMultiplets = function (aSpectrumData, molId) {
	"use strict";

	var i, assignments, delta1, delta2, fix1, fix2, assign1, assign2, spectrum, element1, element2, aTextLine, aMultiplet,
		text = "",
		textElements = [];

	spectrum = new NMRSpectrum(this.doc.getItem(aSpectrumData.id));
	fix1 = aSpectrumData.nucleus[0] === "1H" ? this.CONF.protShiftDecimals : this.CONF.hetShiftDecimals;
	fix2 = aSpectrumData.nucleus[1] === "1H" ? this.CONF.protShiftDecimals : this.CONF.hetShiftDecimals;
	element1 = aSpectrumData.nucleus[0].replace(/[0-9]/g, '');
	element2 = aSpectrumData.nucleus[1].replace(/[0-9]/g, '');

	for (i = 0; i < aSpectrumData.multiplets.count; i++) {
		aMultiplet = aSpectrumData.multiplets.at(i);
		assign1 = undefined;
		assign2 = undefined;
		aTextLine = "";

		delta1 = aMultiplet.chemShift.y;
		delta2 = aMultiplet.chemShift.x;

		assignments = this.assignmentParsers[molId].getFromShiftUUID(aMultiplet.id);
		if (assignments.length) {
			if (element1 !== element2) {
				assign1 = this.assignmentParsers[molId].getFromAtomElement(element1, assignments);
				assign2 = this.assignmentParsers[molId].getFromAtomElement(element2, assignments);
			} else {
				assign1 = this.assignmentParsers[molId].getFromShift(delta1, assignments);
				assign2 = this.assignmentParsers[molId].getFromShift(delta2, assignments);
			}
		}

		aTextLine += this.parse2DAssignment(assign1, delta1.toFixed(fix1));
		aTextLine += this.CONF.corrSeparator;
		aTextLine += this.parse2DAssignment(assign2, delta2.toFixed(fix2)) + this.CONF.separator;
		aTextLine += "E=" + aMultiplet.integralValue(1).toFixed(this.CONF.integralDecimals) + this.CONF.endline;
		if (textElements.indexOf(aTextLine) === -1) {
			textElements.push(aTextLine);
		}
	}

	text = textElements.join("");
	this.sdfText[molId] += text;
};


NMReDATAExporter.prototype.print2DPeaks = function (aSpectrumData, molId) {
	"use strict";

	var i, aPeak, assignments, delta1, delta2, fix1, fix2, assign1, assign2, spectrum, element1, element2, aTextLine,
		text = "",
		textElements = [];

	spectrum = new NMRSpectrum(this.doc.getItem(aSpectrumData.id));
	fix1 = aSpectrumData.nucleus[0] === "1H" ? this.CONF.protShiftDecimals : this.CONF.hetShiftDecimals;
	fix2 = aSpectrumData.nucleus[1] === "1H" ? this.CONF.protShiftDecimals : this.CONF.hetShiftDecimals;
	element1 = aSpectrumData.nucleus[0].replace(/[0-9]/g, '');
	element2 = aSpectrumData.nucleus[1].replace(/[0-9]/g, '');

	for (i = 0; i < aSpectrumData.peaks.count; i++) {
		aPeak = aSpectrumData.peaks.at(i);
		assign1 = undefined;
		assign2 = undefined;
		aTextLine = "";

		if (aPeak.type === Peak.Compound && !this.peakInMultiplets2D(aSpectrumData.multiplets, aPeak)) {
			delta1 = aPeak.delta(1);
			delta2 = aPeak.delta(2);

			assignments = this.assignmentParsers[molId].getFromShiftUUID(aPeak.id);
			if (assignments.length) {
				if (element1 !== element2) {
					assign1 = this.assignmentParsers[molId].getFromAtomElement(element1, assignments);
					assign2 = this.assignmentParsers[molId].getFromAtomElement(element2, assignments);
				} else {
					assign1 = this.assignmentParsers[molId].getFromShift(delta1, assignments);
					assign2 = this.assignmentParsers[molId].getFromShift(delta2, assignments);
				}
			}

			aTextLine += this.parse2DAssignment(assign1, delta1.toFixed(fix1));
			aTextLine += this.CONF.corrSeparator;
			aTextLine += this.parse2DAssignment(assign2, delta2.toFixed(fix2)) + this.CONF.separator;
			aTextLine += "I=" + aPeak.intensity.toFixed(this.CONF.intensityDecimals) + this.CONF.separator;
			aTextLine += "E=" + aPeak.integralInPts(spectrum).toFixed(this.CONF.integralDecimals) + this.CONF.endline;
			if (textElements.indexOf(aTextLine) === -1) {
				textElements.push(aTextLine);
			}
		}
	}

	text = textElements.join("");
	this.sdfText[molId] += text;
};


NMReDATAExporter.prototype.peakInMultiplets2D = function (multiplets, aPeak) {
	"use strict";

	var i, j, peakIds, aMultiplet, rangeMax1, rangeMin1, rangeMax2, rangeMin2, delta1, delta2;

	for (i = 0; i < multiplets.count; i++) {
		aMultiplet = multiplets.at(i);
		peakIds = aMultiplet.peaks;
		for (j = 0; j < peakIds.lenght; j++) {
			if (aPeak.id === peakIds[j]) {
				return true;
			}
		}
		rangeMax1 = aMultiplet.range.bottom;
		rangeMin1 = aMultiplet.range.top;
		rangeMax2 = aMultiplet.range.left;
		rangeMin2 = aMultiplet.range.right;
		delta1 = aPeak.delta(1);
		delta2 = aPeak.delta(2);
		if (delta1 > rangeMin1 && delta1 < rangeMax1 && delta2 > rangeMin2 && delta2 < rangeMax2) {
			return true;
		}
	}
};


NMReDATAExporter.prototype.parse2DAssignment = function (aAssign, aDelta) {
	"use strict";

	var j, text = "";

	if (aAssign && aAssign.length) {
		if (aAssign.length === 1) {
			text += aAssign[0].atom.labelNMReDATA;
		} else {
			text += "(";
			for (j = 0; j < aAssign.length; j++) {
				text += aAssign[j].atom.labelNMReDATA;
				if (j < aAssign.length - 1) {
					text += this.CONF.separator;
				}
			}
			text += ")";
		}
	} else {
		text += aDelta;
	}
	return text;
};


NMReDATAExporter.prototype.print1DPeaks = function (aSpectrumData, molId) {
	"use strict";

	var i, j, aPeak, assignments, spectrum,
		text = "";

	spectrum = new NMRSpectrum(this.doc.getItem(aSpectrumData.id));

	for (i = 0; i < aSpectrumData.peaks.count; i++) {
		aPeak = aSpectrumData.peaks.at(i);

		if (aPeak.type === Peak.Compound) {
			text += aPeak.delta().toFixed(this.CONF.hetShiftDecimals) + this.CONF.separator;
			assignments = this.assignmentParsers[molId].getFromShiftUUID(aPeak.id);

			if (assignments.length) {
				text += "L=";
				if (assignments.length === 1) {
					text += assignments[0].atom.labelNMReDATA + this.CONF.separator;
				} else {
					for (j = 0; j < assignments.length; j++) {
						text += assignments[j].atom.labelNMReDATA + this.CONF.separator;
					}
				}
			}
			text += "I=" + aPeak.intensity.toFixed(this.CONF.intensityDecimals) + this.CONF.separator;
			text += "E=" + aPeak.integralInPts(spectrum).toFixed(this.CONF.integralDecimals) + this.CONF.separator;
			text += "W=" + aPeak.width().toFixed(this.CONF.hetShiftDecimals);
			text += this.CONF.endline;
		}
	}
	this.sdfText[molId] += text;
};


NMReDATAExporter.prototype.print1DMultiplets = function (aSpectrumData, molId) {
	"use strict";

	var i, j, aMultiplet, jText, assignments,
		text = "";

	for (i = 0; i < aSpectrumData.multiplets.count; i++) {
		aMultiplet = aSpectrumData.multiplets.at(i);
		text += aMultiplet.rangeMin.toFixed(this.CONF.hetShiftDecimals) + "-" + aMultiplet.rangeMax.toFixed(this.CONF.hetShiftDecimals) + this.CONF.separator;
		text += "S=" + aMultiplet.category + this.CONF.separator;
		assignments = this.assignmentParsers[molId].getFromShiftUUID(aMultiplet.uuid);

		if (assignments.length) {
			text += "L=";
			if (assignments.length === 1) {
				text += assignments[0].atom.labelNMReDATA + this.CONF.separator;
				if (assignments[0].numberOfEqAtoms) {
					text += "N=" + assignments[0].numberOfEqAtoms + this.CONF.separator;
				} else {
					text += "N=1" + this.CONF.separator;
				}
			} else {
				for (j = 0; j < assignments.length; j++) {
					text += assignments[j].atom.labelNMReDATA + this.CONF.separator;
				}
				text += "N=";
				for (j = 0; j < assignments.length; j++) {
					if (assignments[0].numberOfEqAtoms) {
						text += assignments[j].numberOfEqAtoms + this.CONF.separator;
					} else {
						text += "1" + this.CONF.separator;
					}
				}
			}
		}
		text += "E=" + aMultiplet.integralValue(1).toFixed(this.CONF.integralDecimals) + this.CONF.separator;
		jText = this.parseMultipletJList(aMultiplet.jList(true), assignments, molId);
		text += "J=" + jText + this.CONF.endline;
	}
	this.sdfText[molId] += text;
};


NMReDATAExporter.prototype.parseMultipletJList = function (aJList, aAssignments, molId) {
	"use strict";

	var j, jArray = [];

	function greaterThan(a, b) {
		return b - a;
	}

	for (j = 0; j < aJList.length; j++) {
		jArray[j] = aJList.at(j).toFixed(this.CONF.jCouplingDecimals);
	}
	jArray.sort(greaterThan);
	this.assignJcouplings(jArray, aAssignments, molId);

	return jArray.join(",");
};


NMReDATAExporter.prototype.assignJcouplings = function (aJArray, aAssignments, molId) {
	"use strict";

	var i, j, k, partner, assignmentText;

	for (i = 0; i < aJArray.length; i++) {
		for (j = 0; j < aAssignments.length; j++) {
			assignmentText = "";
			if (aAssignments[j].couplings && aAssignments[j].couplings.js) {
				for (k = 0; k < aAssignments[j].couplings.js.length; k++) {
					if (Math.abs(aJArray[i] - aAssignments[j].couplings.js[k].value) < this.CONF.jCouplingTol) {
						partner = this.assignmentParsers[molId].getFromAtom(aAssignments[j].couplings.js[k].atom);
						if (partner) {
							if (!assignmentText) {
								assignmentText += "(" + partner.atom.labelNMReDATA;
							} else {
								assignmentText += "," + partner.atom.labelNMReDATA;
							}
						}
					}
				}
			}
		}
		if (assignmentText) {
			aJArray[i] += assignmentText += ")";
		}
	}
};

NMReDATAExporter.prototype.calculateMD5 = function (aFilePath) {
	"use strict";

	var aFile, md5 = "";

	aFile = new File(aFilePath);
	if (aFile.open(File.ReadOnly)) {
		md5 = aFile.hash("md5");
	}
	return md5;
};

NMReDATAExporter.prototype.getSpectrumTagName = function (aSpectrumData, molId) {
	"use strict";

	var i, mixingType,
		tagName = "NMREDATA_";

	if (!this.usedSpectralTagNames[molId]) {
		this.usedSpectralTagNames[molId] = {};
	}

	if (aSpectrumData.type === "1D") {
		tagName += aSpectrumData.type + "_" + aSpectrumData.nucleus[0];

		if (!this.usedSpectralTagNames[molId][tagName]) {
			this.usedSpectralTagNames[molId][tagName] = true;
			return tagName;
		}
		for (i = 2; i < this.spectra.length + 1; i++) {
			if (!this.usedSpectralTagNames[tagName + "#" + i]) {
				this.usedSpectralTagNames[tagName + "#" + i] = true;
				return tagName + "#" + i;
			}
		}

	} else if (aSpectrumData.type === "2D") {
		tagName += aSpectrumData.type + "_" + aSpectrumData.nucleus[0];
		mixingType = this.getSpectrumMixingType(aSpectrumData.experimentType);

		if (mixingType) {
			tagName += "_" + mixingType + "_" + aSpectrumData.nucleus[1];
		}

		if (!this.usedSpectralTagNames[molId][tagName]) {
			this.usedSpectralTagNames[molId][tagName] = true;
			return tagName;
		}
		for (i = 2; i < this.spectra.length + 1; i++) {
			if (!this.usedSpectralTagNames[molId][tagName + "#" + i]) {
				this.usedSpectralTagNames[molId][tagName + "#" + i] = true;
				return tagName + "#" + i;
			}
		}
	}
};


NMReDATAExporter.prototype.getSpectrumMixingType = function (aExperimentType) {
	"use strict";

	var type2D, mixingTypes;

	type2D = aExperimentType.substring(3);

	mixingTypes = {};
	mixingTypes.COSY                 = "NJ";
	mixingTypes.DOSY                 = "F";
	mixingTypes["DQF-COSY"]          = "NJ";
	mixingTypes.H2BC                 = "2J";
	mixingTypes.HETCOR               = "1J";
	mixingTypes.HMBC                 = "NJ";
	mixingTypes.HMQC                 = "1J";
	mixingTypes["HMQC-MB"]           = "1J";
	mixingTypes.HSQC                 = "1J";
	mixingTypes["HSQC-EDITED"]       = "1J";
	mixingTypes["HSQC-TOCSY"]        = "1J(1H_TJ)";
	mixingTypes["HSQC-TOCSY-EDITED"] = "1J(1H_TJ)";
	mixingTypes.INADEQUATE           = "1J";
	mixingTypes.JRES                 = "";	// This type of experiments will have a simplified Tag name NMREDATA_2D_1H
	mixingTypes.NOESY                = "D";
	mixingTypes.ROESY                = "D";
	mixingTypes.TOCSY                = "TJ";
	mixingTypes.HOESY                = "D";	//Not supported by Mnova yet

	return mixingTypes[type2D];

};


NMReDATAExporter.prototype.getMoleculeIds = function () {
	"use strict";

	var i, molecules, dataId,
		tempMoleculeIds = {};

	molecules = this.doc.itemsByName("Molecule");

	for (i = 0; i < molecules.length; i++) {
		if (i === 0) {
			tempMoleculeIds[molecules[i].dataId] = molecules[i].uuid;
		} else if (!tempMoleculeIds[molecules[i].dataId]) {
			tempMoleculeIds[molecules[i].dataId] = molecules[i].uuid;
		}
	}

	for (dataId in tempMoleculeIds) {
		if (tempMoleculeIds.hasOwnProperty(dataId)) {
			this.moleculeIds.push(tempMoleculeIds[dataId]);
		}
	}
};


NMReDATAExporter.prototype.loadMolecularAssignmentsParsers = function () {
	"use strict";

	var i, molId, molecule;

	for (i = 0; i < this.moleculeIds.length; i++) {
		molId = this.moleculeIds[i];
		molecule = new Molecule(this.doc.getItem(molId));
		this.assignmentParsers[molId] = new MolecularAssignmentsParser(molecule);
	}
};


NMReDATAExporter.prototype.getSpectra = function () {
	"use strict";

	var i, spectra;

	spectra = this.doc.itemsByName("NMR Spectrum");

	for (i = 0; i < spectra.length; i++) {
		this.spectra.push(this.parseSpectrum(new NMRSpectrum(spectra[i])));
	}
};


NMReDATAExporter.prototype.parseSpectrum = function (aSpectrum) {
	"use strict";

	var originalDir, aTemplatePath, aTemplateName,
		i = 1,
		data = {};

	data.id               = aSpectrum.uuid;
	data.type             = aSpectrum.type;
	data.experimentType   = aSpectrum.experimentType;
	if (data.type === "1D") {
		data.nucleus          = [ aSpectrum.nucleus() ];
	} else if (data.type === "2D") {
		data.nucleus          = [ aSpectrum.nucleus(1), aSpectrum.nucleus(2) ];
	}
	data.solvent          = aSpectrum.solvent || aSpectrum.getParam("Solvent");
	if (!this.ignoreFilePaths) {
		data.originalFileName = this.checkSpectrumFileName(aSpectrum.originalFileName);
		if (data.originalFileName) {
			data.processing = new NMRProcessing(aSpectrum.proc);
			data.processing.setParameter("Mult.Apply", false);
			data.processing.setParameter("PP.Apply", false);
			data.processing.setParameter("Integration.Apply", false);
			originalDir = new Dir(new File(data.originalFileName).absDirPath);
			aTemplateName = "mnova.mnp";
			aTemplatePath = originalDir.filePath("mnova.mnp");
			while (File.exists(aTemplatePath)) {
				aTemplateName = "mnova" + i + ".mnp";
				aTemplatePath = originalDir.filePath(aTemplateName);
				i++;
			}
			data.processingTemplateName = aTemplateName;
			data.processingTemplate = aTemplatePath;
			data.processing.save(data.processingTemplate);
			this.addDirToZip(data.originalFileName);
		}
	} else {
		data.originalFileName = "";
	}
	data.temperature      = aSpectrum.temperature || aSpectrum.getParam("Temperature");
	data.frequency        = aSpectrum.frequency() || aSpectrum.getParam("Spectrometer Frequency");
	data.pulseProgram     = aSpectrum.getParam("Pulse Sequence");
	data.peaks            = new Peaks(aSpectrum.peaks());
	data.multiplets       = new Multiplets(aSpectrum.multiplets());

	return data;
};


NMReDATAExporter.prototype.checkSpectrumFileName = function (originalFilePath) {
	"use strict";

	var docPath, dirPath, expectedFilePath, fileName, correctFilePath = "";

	if (File.exists(originalFilePath)) {
		return originalFilePath;
	}

	if (this.orgFilePathCorrected) {
		expectedFilePath = originalFilePath.replace(this.rootPathEq.ori, this.rootPathEq.curr);
		if (File.exists(expectedFilePath)) {
			return expectedFilePath;
		}
		dirPath = this.rootPathEq.curr;
	} else {
		docPath = this.doc.name;
		dirPath = docPath.substring(0, Math.max(docPath.lastIndexOf("/"), docPath.lastIndexOf("\\")));
	}

	fileName = originalFilePath.split("/")[originalFilePath.split("/").length - 1];
	correctFilePath = FileDialog.getOpenFileName(fileName, "Original file: " + originalFilePath + " doesnot exist, enter new location", dirPath);

	if (correctFilePath) {
		this.orgFilePathCorrected = true;
		this.rootPathEq = this.getRootPathEquivalent(originalFilePath, correctFilePath);
	} else {
		this.ignoreFilePaths = true;
	}

	return correctFilePath;
};


NMReDATAExporter.prototype.addDirToZip = function (aFilePath) {
	"use strict";

	var baseDirPath,
		dataDir = new Dir(File.absDirPath(aFilePath));

	if (aFilePath.endsWith("1r") || aFilePath.endsWith("2rr") || aFilePath.endsWith("3rrr")) {
		dataDir.cdUp();
		dataDir.cdUp();
	}
	baseDirPath = dataDir.absPath;
	if (this.rootPathEq && this.rootPathEq.curr) {
		NMReDATACommon.addFilesToZip(baseDirPath, this.outputFile, this.rootPathEq.curr);
	} else {
		NMReDATACommon.addFilesToZip(baseDirPath, this.outputFile);
	}
};


NMReDATAExporter.prototype.getRootPathEquivalent = function (orgPath, curPath) {
	"use strict";

	var end1, end2,
		rootPathEq = {};

	while (true) {
		end1 = orgPath.substring(Math.max(orgPath.lastIndexOf("/"), orgPath.lastIndexOf("\\")));
		end2 = curPath.substring(Math.max(curPath.lastIndexOf("/"), curPath.lastIndexOf("\\")));

		if (end1 !== end2) {
			break;
		}
		orgPath = orgPath.substring(0, Math.max(orgPath.lastIndexOf("/"), orgPath.lastIndexOf("\\")));
		curPath = curPath.substring(0, Math.max(curPath.lastIndexOf("/"), curPath.lastIndexOf("\\")));
	}

	rootPathEq.ori = orgPath;
	rootPathEq.curr = curPath;

	return rootPathEq;
};


NMReDATAExporter.prototype.printProcessingTemplatesTag = function (index) {
	"use strict";

	var i, data, relativePath, relativeSpectrumLocation, spectrumName, lastSlash,
		molId = this.moleculeIds[index];

	this.sdfText[molId] += this.CONF.tagStart + "MNOVA_PROC_TEMPLATES>\n";

	for (i = 0; i < this.spectra.length; i++) {
		data = this.spectra[i];
		if (this.rootPathEq) {
			relativePath = data.processingTemplate.replace(this.rootPathEq.curr, "file:.");
		} else if (!this.ignoreFilePaths) {
			relativeSpectrumLocation = this.getRelativeSpectrumLocation(data.originalFileName);
			if (File.absDirPath(data.processingTemplate) === File.absDirPath(data.originalFileName)) {
				lastSlash = 1 + Math.max(relativeSpectrumLocation.lastIndexOf("/"), relativeSpectrumLocation.lastIndexOf("\\"));
				spectrumName = relativeSpectrumLocation.slice(lastSlash);
				relativePath = relativeSpectrumLocation.replace(spectrumName, data.processingTemplateName);
			}
		}
		this.sdfText[molId] += data.spectrumTagName + "=" + relativePath + this.CONF.endline;
	}
};


NMReDATAExporter.prototype.deleteSavedProcessingTemplates = function () {
	"use strict";

	var i, data;

	for (i = 0; i < this.spectra.length; i++) {
		data = this.spectra[i];
		if (File.exists(data.processingTemplate)) {
			File.remove(data.processingTemplate);
		}
	}
};


NMReDATAExporter.prototype.completeSDF = function (index) {
	"use strict";

	var molId = this.moleculeIds[index];

	this.sdfText[molId] += "\n$$$$\n";
};


NMReDATAExporter.prototype.saveTextToFile = function (aText, aFilePath) {
	"use strict";

	var stream, aFile;

	aFile = new File(aFilePath);
	aFile.open(File.WriteOnly);
	stream = new TextStream(aFile);
	stream.write(aText);
	stream.flush();
	aFile.close();
};
